package net.cloudcodex.server.test;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.cloudcodex.server.Context;
import net.cloudcodex.server.data.AdvancedDAO;
import net.cloudcodex.server.data.Data;
import net.cloudcodex.server.data.Data.Campaign;
import net.cloudcodex.server.data.Data.Message;
import net.cloudcodex.server.data.Data.Scene;
import net.cloudcodex.server.data.campaign.msg.SceneSDO;
import net.cloudcodex.server.service.CampaignService;
import net.cloudcodex.server.service.HomeService;
import net.cloudcodex.server.service.MessageService;
import net.cloudcodex.shared.MessageAction;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;


public class MessageTester {

    private final LocalServiceTestHelper helper =
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

    private CampaignService campaignService;

    private MessageService messageService;

    private HomeService homeService;

    private AdvancedDAO dao;
    
    private Data.User master;
    private Data.User player1;
    private Data.User player2;
    private Data.User player3;
    private Campaign campaign;
    private long campaignId;
    private Data.Character char1;
    private long char1Id;
    private Data.Character char2;
    private long char2Id;
    private Data.Character char3;
    private long char3Id;
    private Data.Character npc1;
    private long npc1Id;
    private Data.Character npc2;
    private long npc2Id;
    private Data.Character npc3;
    private long npc3Id;
    
    @Before
    public void setUp() {
        helper.setUp();
        DatastoreService store = DatastoreServiceFactory.getDatastoreService();
        campaignService = new CampaignService(store);
        messageService = new MessageService(store);
        homeService = new HomeService(store);
        dao = new AdvancedDAO(store);
        
		master = homeService.createUser(null, "master@test.com", "Master");
    	player1 = homeService.createUser(null, "player1@test.com", "Player1");
		player2 = homeService.createUser(null, "player2@test.com", "Player2");
		player3 = homeService.createUser(null, "player3@test.com", "Player3");
		
		campaign = campaignService.createCampaign(null, "Test Campaign", "Some game", "Some desc", null, master);
		campaignId = campaign.getKey().getId();
		
		char1 = campaignService.createCharacter(null, campaign, "Char1", player1, null, null);
		char1Id = char1.getKey().getId();
		char2 = campaignService.createCharacter(null, campaign, "Char2", player2, null, null);
		char2Id = char2.getKey().getId();
		char3 = campaignService.createCharacter(null, campaign, "Char3", player3, null, null);
		char3Id = char3.getKey().getId();
		
		npc1 = campaignService.createCharacter(null, campaign, "NPC1", null, null, null);
		npc1Id = npc1.getKey().getId();
		npc2 = campaignService.createCharacter(null, campaign, "NPC2", null, null, null);
		npc2Id = npc2.getKey().getId();
		npc3 = campaignService.createCharacter(null, campaign, "NPC3", null, null, null);
		npc3Id = npc3.getKey().getId();
    }

    @After
    public void tearDown() {
        helper.tearDown();
        campaignService = null;
        homeService = null;
        dao = null;
    }

    @Test
    public void test1() {
    	
    	final Context context = new Context(player1);

    	// Remember that dice of others cannot be seen by the player, they're just here.
    	
    	System.out.println(messageService.justForTestsCreateSequenceRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemRollDicesRandomly(context, campaignId, char1Id));
    	
    	System.out.println(messageService.justForTestsCreateSequenceRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemRollDicesRandomly(context, campaignId, char1Id));

    	System.out.println(messageService.justForTestsCreateSequenceRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemTalkRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsMakeThemRollDicesRandomly(context, campaignId, char1Id));
    	
    	System.out.println(messageService.justForTestsDeleteMessageRandomly(context, campaignId, char1Id));
    	System.out.println(messageService.justForTestsInsertOFFRandomly(context, campaignId, char1Id));
    	
    	{
        	final List<SceneSDO> scenes = messageService.getMessages(context, 
        			campaignId, char1Id, null, null);

	    	System.out.println(messageService.playerPostAction(
					context, campaignId, char1Id, 
					scenes.get(scenes.size() - 1).getScene().getKey().getId(), new Date(),
					MessageAction.WHISP, "This is a whisp"));
    		
    	}
    	
    	{
        	List<Scene> scenes = dao.asListOfScenes(null, dao.queryScene(campaign.getKey()), null);
    		if(scenes != null) {
    			for(Scene seq : scenes) {
    				System.err.println(seq.getEntity());
    				final List<Message> messages = 
    					dao.asListOfMessages(null, 
    						dao.queryMessage(seq.getKey()), null, 
    						Message.Properties.TIMESTAMP);
    				if(messages != null) {
    					for(Message msg : messages) {
    						System.err.println(msg.getEntity());
    					}
    				}
    			}
    		}
    	}
    	
    	dumpMessages(context, campaignId, char1Id);
    	System.out.println(messageService.justForTestsReindexRandomly(context, campaignId, char1Id));
    	dumpMessages(context, campaignId, char1Id);

    }
    
    public static class IndexMessageComparator implements Comparator<Message> {

		@Override
		public int compare(Message o1, Message o2) {
			if(o1 == null && o2 == null) {
				return 0;
			}
			if(o1 == null) {
				return -1;
			}
			if(o2 == null) {
				return 1;
			}
			return o1.getIndex().compareTo(o2.getIndex());
		}
		
	}
    
    private void dumpMessages(Context context, long campaignId, long characterId) {
    	
    	System.out.println("----------------------------------------");
    	final List<SceneSDO> scenes = messageService.getMessages(context, campaignId, characterId, null, null);
    	for(SceneSDO sdo  : scenes) {
    		
    		final Map<Key, Data.Character> map = new HashMap<Key, Data.Character>();
    		final StringBuffer buffer = new StringBuffer("Sequence with : ");
    		for(Data.Character character : sdo.getCharacters()) {
    			buffer.append(character.getName()).append(", ");
    			map.put(character.getKey(), character);
    		}
    		System.out.println(buffer.toString());
    		
    		Collections.sort(sdo.getMessages(), new IndexMessageComparator());
    		for(Message message : sdo.getMessages()) {
    			final Data.Character character = map.get(message.getAuthor());
    			final String author = character == null ? "GM" : character.getName();
    			System.out.println("\t" + author + "(" + message.getKey().getId() + ") : " + message.getContent());
    		}
    	}
    }
	
}
